#include "BattleField.hpp"

#include "siut/simd/Mat4f.hpp"

using namespace siut;
using siut::simd::Mat4f;

BattleField::BattleField()
{
  scale = 200;
  min = -scale;
  max = scale;
  range = max + abs(min);

  mPickedPosition = Vec3f(0.0f);
  isPickUpdated_ = false;

  gridX = 0;
  gridY = 0;

  gridWidth = 20;
  gridHeight = 20;

  xscale = range / float(gridWidth);
  yscale = range / float(gridHeight);
  
  // Set all tiles empty.
  std::vector<int> v1(gridHeight, EMPTY);
  tileState_ = std::vector< std::vector<int> >(gridWidth, v1);
}

BattleField::~BattleField()
{
  ReleaseFBO();
}

void BattleField::ReleaseFBO()
{
	glDeleteRenderbuffersEXT(1, &color_rb);
  glDeleteFramebuffersEXT(1, &fb);
  glDeleteBuffers(1, &fb);
}

void BattleField::privateInit()
{
  // Create vertex arrays
  // ... just using immidiate mode geom right now...

  glGenFramebuffersEXT(1, &fb);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb); // Switch to framebuffer so things
	glGenRenderbuffersEXT(1, &color_rb); // Make color render buffer
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, color_rb);
	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB8, 512, 512); // 8-bits RGB no Alpha
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, color_rb);
	//------
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, color_rb);
	//------
  // Go back to regular frame buffer rendering
  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

	// Does the GPU support current FBO config?
	GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
	switch(status)
	{
	case GL_FRAMEBUFFER_COMPLETE_EXT: std::cout << "Framebuffer OK" << std::endl; break;
		default:
			std::cout << __FILE__ << ": Framebuffer error";
			exit(0);
	}
}

void BattleField::privateRender()
{
  // Render the battlefield

  // Render picking colors to FBO
  renderPickColors();

  glBegin(GL_QUADS);
	glColor3f(0,.5f,0);  glVertex3f(-scale,0,scale); // top left, X = 0, Y = 1
	glColor3f(0,.5f,0);  glVertex3f(scale,0,scale); // top right, X = 1, Y = 1
	glColor3f(0,.5f,0);  glVertex3f(scale,0,-scale); // bottom right, X = 0, Y = 0;
	glColor3f(0,.5f,0);  glVertex3f(-scale,0,-scale); // bottom left, X = 0, Y = 0
  glEnd();

  glPushMatrix();
  glTranslatef(-scale, .1f, -scale);
  glColor3f(1,1,1);
  glBegin(GL_LINES);
	for(int i=0; i<gridWidth+1; i++)
	{
	  glVertex3f(xscale*i, .5, 0);
	  glVertex3f(xscale*i, .5, yscale*gridHeight);
	  for(int j=0; j<gridHeight+1; j++)
	  {
		glVertex3f(0, .5, yscale*j);
		glVertex3f(xscale*gridWidth, .5, yscale*j);
	  }
	}
  glEnd();
  glPopMatrix();
  

  if( pickedPosEmpty() )
  {
	glColor4f(0,1,0,.5f);
  }
  else
  {
	glColor4f(1,0,0,.5f);
  }

  glPushMatrix();
	//glTranslatef( mPickedPosition[0], .1, mPickedPosition[2] );
	glTranslatef( xscale/2 + min + range*float(gridX)/float(gridWidth), .9f, yscale/2 + min + range*float(gridY)/float(gridHeight));

	glBegin(GL_QUADS);
	  glVertex3f(-xscale/2,0,-yscale/2);
	  glVertex3f(-xscale/2,0,yscale/2);
	  glVertex3f(xscale/2,0,yscale/2);
	  glVertex3f(xscale/2,0,-yscale/2);
	  //glVertex3f(0,0,0);
	  //glVertex3f(0,0,yscale);
	  //glVertex3f(xscale,0,yscale);
	  //glVertex3f(xscale,0,0);
	glEnd();
  glPopMatrix();

  // Draw some scenery
  glColor3f(1,1,1);
  float stuffScale = 300.0f;
  glutWireCube(stuffScale*2);

  // 6 surfaces of glut geometry
  float s = 50;
  

  for(int i=0; i<6; i++)
  for(int j=0; j<10; j++)
  for(int k=0; k<10; k++)
  {
	glColor3f(.2f + float(i)/6, .2f + float(j)/10.0f, .2f + float(k)/10.0f);
	  glPushMatrix();
	  switch(i)
	  {
		case 0: glTranslatef(stuffScale, stuffScale - j*s, stuffScale-k*s); break;
		case 1: glTranslatef(-stuffScale, stuffScale - j*s, stuffScale-k*s); break;
		case 2: glTranslatef(stuffScale - j*s,stuffScale-k*s,stuffScale); break;
		case 3: glTranslatef(stuffScale - j*s,stuffScale-k*s,-stuffScale); break;
		case 4: glTranslatef(stuffScale - j*s,stuffScale,stuffScale-k*s); break;
		//case 5: glTranslatef(250 - j*s,-250,250-k*s); break;
		default: glPopMatrix(); continue; break; // dont draw anything.
	  }
	  glScalef(25,25,25);
	  glutWireRhombicDodecahedron();
	  glPopMatrix();
  }
}

void BattleField::privateUpdate()
{
}

void BattleField::renderPickColors()
{
	GLint viewport[4];							// Where The Viewport Values Will Be Stored
	glGetIntegerv(GL_VIEWPORT, viewport);			// Retrieves The Viewport Values (X, Y, Width, Height)  
	int oldwidth = viewport[2];
	int oldheight = viewport[3];


	int fboSize = 512;
	glViewport (0, 0, fboSize, fboSize);

	//glDrawBuffer (GL_NONE);
	//glReadBuffer(GL_NONE);

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);

	//glBindTexture(GL_TEXTURE_2D, 0);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb);
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, color_rb);



	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Render colorpick quad with interpolated colors. Use red and blue components
	// X-axis is red, x goes left->right
	// Y-axis is blue, y goes bottom->top
	glBegin(GL_QUADS);
	glColor3f(0,0,1);  glVertex3f(-scale,0,scale); // top left, X = 0, Y = 1
	glColor3f(1,0,1);  glVertex3f(scale,0,scale); // top right, X = 1, Y = 1
	glColor3f(1,0,0);  glVertex3f(scale,0,-scale); // bottom right, X = 0, Y = 0;
	glColor3f(0,0,0);  glVertex3f(-scale,0,-scale); // bottom left, X = 0, Y = 0
	glEnd();

  if( !isPickUpdated_ )
  {
		isPickUpdated_ = true;
		float color[3];																	// Store read colors.
		int mouseScaleX = int( float(fboSize)*(float(mPickX))/float(oldwidth) );			// normalize mousecoordinates, then scale by FBO-buffer size.
		int mouseScaleY = int( float(fboSize)*(float(mPickY))/float(oldheight) );
		glReadPixels( mouseScaleX, fboSize-mouseScaleY , 1, 1, GL_RGB, GL_FLOAT, color); // read 1 pixel at mousecoords.

		if(color[0] > 0.01f && color[2] > 0.01f) // if color isnt black then update, else keep old position.
		{
			float normalizedPickX = color[0]; // add scale to take -scale,scale range to 0, 2*scale range. Then divide by 2*scale for 0,1 range.
			float normalizedPickZ = color[2];
			gridX = int( ( float(gridWidth) * normalizedPickX) );
			gridY = int( ( float(gridHeight) * normalizedPickZ) );

			// Keep picked integer positions within boundries. 
			gridX = std::min<int>(gridWidth-1, std::max<int>(0, gridX) );
			gridY = std::min<int>(gridHeight-1, std::max<int>(0, gridY) );

			// integer position scaled by real scale, objects placed on battlefield are positioned at discrete positions, not continous floats
			mPickedPosition = Vec3f( xscale/2 + min + range*float(gridX)/float(gridWidth), .1f, yscale/2 + min + range*float(gridY)/float(gridHeight) ); 
		  
			// the continous position would be:
			//mPickedPosition = Vec3f( min+range*normalizedPickX, 0, min+range*normalizedPickZ );
		}

  }
  
	// Unbind FBO
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

	// Set viewport back
	glViewport (0, 0, oldwidth,oldheight);
}

void BattleField::setPickPoint(int x, int y)
{
  mPickX = x;
  mPickY = y;
  isPickUpdated_ = false;
}

Vec3f *BattleField::getPickedPos()
{
  return &mPickedPosition;
}

bool BattleField::pickedPosEmpty()
{
  return tileState_[gridX][gridY] == EMPTY;
}

void BattleField::setActiveTileAsTower()
{
  tileState_[gridX][gridY] = TURRETTILE;
}

void BattleField::getRealCoordFromInteger(int getX, int getY, float &gridPosX, float &gridPosY)
{
  gridPosX = xscale/2 + min + range*float(getX)/float(gridWidth);
  gridPosY = yscale/2 + min + range*float(getY)/float(gridHeight);
}

void BattleField::getScale(float &xscale, float &yscale)
{
  float scale = 200;
  float min = -scale;
  float max = scale;
  float range = max + abs(min);
  xscale = range / float(gridWidth);
  yscale = range / float(gridHeight);
}

void BattleField::setTileToPath(int tileX, int tileY)
{
  assert(gridX >= 0 && gridX < gridWidth);
  assert(gridY >= 0 && gridY < gridHeight);
  tileState_[tileX][tileY] = PATHTILE;
}

